// 1.3 device token
// 1.8.2重新获取device token
// 生成设备token
use std::{str::FromStr};

use anyhow::anyhow;
use serde::{Serialize, Deserialize};
use super::get_jwt::JWT_INSTANCE;


/// 顶层认证请求结构体（字段名与JSON完全一致）
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthRequest {
    pub Properties: Properties,
    pub RelyingParty: String,
    pub TokenType: String,
}

/// Properties字段结构体
#[derive(Debug, Serialize, Deserialize)]
pub struct Properties {
    pub AuthMethod: String,
    pub Id: String, // 格式为"{UUID}"
    pub DeviceType: String,
    pub SerialNumber: String, // 格式为"{UUID}"
    pub Version: String,
    pub ProofKey: ProofKey,
}

/// ProofKey字段结构体
#[derive(Debug, Serialize, Deserialize)]
struct ProofKey {
    #[serde(rename = "use")] // 特殊处理：JSON中是小写use，与Rust关键字冲突
    Use: String,
    alg: String,
    kty: String,
    crv: String,
    x: String,
    y: String,
}

impl AuthRequest {
    /// 创建一个新的认证请求实例
    async fn new() -> Self {
        // 生成UUID并格式化为"{UUID}"形式
        let uuid_structure = get_uuid().await;
        let uuid_device_id = uuid_structure.uuid_device_id;
        let uuid_device_id = format!("{{{}}}", uuid_device_id);
        let uuid_serial_number = format!("{{{}}}", uuid_structure.uuid_serial_number);

        AuthRequest {
            Properties: Properties {
                AuthMethod: "ProofOfPossession".to_string(),
                Id: uuid_device_id,
                DeviceType: "Android".to_string(),
                SerialNumber: uuid_serial_number,
                Version: "15.0".to_string(),
                ProofKey: ProofKey {
                    Use: "sig".to_string(),
                    alg: "ES256".to_string(),
                    kty: "EC".to_string(),
                    crv: "P-256".to_string(),
                    x: JWT_INSTANCE.get().unwrap().x_b64.to_string(),
                    y: JWT_INSTANCE.get().unwrap().y_b64.to_string(),
                },
            },
            RelyingParty: "http://auth.xboxlive.com".to_string(),
            TokenType: "JWT".to_string(),
        }
    }
}

#[derive(Debug,Serialize,Deserialize)]
struct response_token{
    NotAfter:String,
    Token:String
}


use reqwest::Client;
use crate::{api::{get_signature::get_signature, get_uuid::get_uuid}, db::{db_insert::db_insert, db_select::db_select}};
use anyhow::Result;
use chrono::{DateTime, Utc};

pub async fn get_device_token() -> Result<String> {

    { // 检查数据库中的device_token是否过期

        if let Ok(config) = db_select("device_token_not_after").await {
            let expiry:DateTime<Utc> = DateTime::from_str(&config.value).expect("invalid datetime format");
            let now = Utc::now();
            if(now < expiry){
                // 没过期，直接返回
                return Ok(db_select("device_token").await.unwrap().value);
            }
        }
    }

    let client = Client::new();
    let auth_request = AuthRequest::new().await;

    let body = serde_json::to_string_pretty(&auth_request)?;

    println!("body:{}", body);

    let response = client.post("https://device.auth.xboxlive.com/device/authenticate")
        .header("x-xbl-contract-version", "1")
        .header("Cache-Control", "no-store, must-revalidate, no-cache")
        .header("Signature", get_signature("https://device.auth.xboxlive.com/device/authenticate", "", &body))
        // .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36")
        .body(body)
        .send().await?;
        // .status().as_str().to_string();
        // .text().await?.to_string();

    let response_code :u16= response.status().as_u16();
    let response_text = response.text().await?;

    println!("Device Auth Response: {}", response_text);

    match response_code {
        200 => {
            let token:response_token = serde_json::from_str(&response_text)?;
            db_insert("device_token", &token.Token).await.unwrap();
            db_insert("device_token_not_after", &token.NotAfter).await.unwrap();
            return Ok(token.Token);
        }
        // 403 => {
        //     return Err("the server prohibit, you may visit for too many times".into());
        // }
        _ => {
            return Err(anyhow!("device_token fail to get, status code:{}", response_code));
        }
    }

}